﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace EdexApiClient
{
    public partial class EdexApiContext
    {
        public string ApiUri { get; set;}
        public string RootUri { get; set; } 

        private string email { get; set; }
        private string password { get; set; }
        public API_SESSION session { get; set; }

        public EdexApiContext()
        {
            this.ApiUri = System.Configuration.ConfigurationManager.AppSettings["ApiUri"];
            this.RootUri = System.Configuration.ConfigurationManager.AppSettings["RootUri"];
        }

        public EdexApiContext(string apiUri, string rootUri, string email, string password)
        {
            this.ApiUri = apiUri;
            this.RootUri = rootUri;

            this.email = email;
            this.password = password;

            this.session = this.GetSession(email, password);
        }

        public EdexApiContext(string email, string password)
        {
            this.ApiUri = System.Configuration.ConfigurationManager.AppSettings["ApiUri"];
            this.RootUri = System.Configuration.ConfigurationManager.AppSettings["RootUri"];

            this.email = email;
            this.password = password;

            this.session = this.GetSession(email, password);
        }

        public EdexApiContext(string apiKey)
        {
            this.ApiUri = System.Configuration.ConfigurationManager.AppSettings["ApiUri"];
            this.RootUri = System.Configuration.ConfigurationManager.AppSettings["RootUri"];

            this.session = this.GetSession(apiKey);
        }

        private API_SESSION GetSession(string email, string password)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "security/login/?email={0}&password={1}");
                var result = client.GetAsync(String.Format(uri, email, password)).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);

                var js = new System.Web.Script.Serialization.JavaScriptSerializer();
                return js.Deserialize<API_SESSION>(result.Content.ReadAsStringAsync().Result);
            }
        }

        private API_SESSION GetSession(string api_key)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "security/login/?api_key={0}");
                var result = client.GetAsync(String.Format(uri, api_key)).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);

                var js = new System.Web.Script.Serialization.JavaScriptSerializer();
                return js.Deserialize<API_SESSION>(result.Content.ReadAsStringAsync().Result);
            }
        }

        public API_SESSION Register(string name, string email)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "security/Register/");
                var result = client.PostAsJsonAsync<UserRegisterDetails>(uri,
                    new UserRegisterDetails { Email = email, Name = name }).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);

                var js = new System.Web.Script.Serialization.JavaScriptSerializer();
                return js.Deserialize<API_SESSION>(result.Content.ReadAsStringAsync().Result);
            }
        }

        public API_SESSION Register(SEC_USERS user)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "security/Register/");
                var result = client.PostAsJsonAsync<SEC_USERS>(uri, user).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);

                var js = new System.Web.Script.Serialization.JavaScriptSerializer();
                return js.Deserialize<API_SESSION>(result.Content.ReadAsStringAsync().Result);
            }
        }

        public void Reset(string email)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "security/Reset/");
                var result = client.PostAsJsonAsync<UserRegisterDetails>(uri,
                    new UserRegisterDetails { Email = email }).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);
            }
        }

        public void ChangePassword(string password, string new_password)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "security/ChangePassword/?password={0}&new_password={1}&api_key={2}");
                uri = String.Format(uri, password, new_password, this.session.APIKEY);
                var result = client.GetAsync(uri).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);
            }
        }

        public void ChangeUserInfo(SEC_USERS user)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "security/ChangeUserInfo/?api_key={0}");
                uri = String.Format(uri, this.session.APIKEY);

                var result = client.PostAsJsonAsync<SEC_USERS>(uri, user).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);
            }
        }

        public void ChangeCompany(string company_key)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "security/ChangeCompany/?api_key={0}&company_key={1}");
                var result = client.GetAsync(String.Format(uri, this.session.APIKEY, company_key)).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);
            }
        }

        public void AccessToUser(string email, string company_key)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "security/AccessToUser/?email={0}&company_key={1}");
                var result = client.GetAsync(String.Format(uri, email, company_key)).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);
            }
        }

        public void CheckConstraints()
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "document/CheckConstraints/?api_key={0}");
                var result = client.GetAsync(String.Format(uri, this.session.APIKEY)).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);
            }
        }

        public void SetIncomingNumber(string id, string incomingNumber)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var uri = System.IO.Path.Combine(this.RootUri, "document/SetIncomingNumber/?api_key={0}&id={1}&incomingNumber={2}");
                var result = client.GetAsync(String.Format(uri, this.session.APIKEY, id, incomingNumber)).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);
            }
        }

        private T GetData<T>(string uri)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var apiUri = System.IO.Path.Combine(this.ApiUri, uri);

                var js = new System.Web.Script.Serialization.JavaScriptSerializer();
                var result = client.GetAsync(String.Format(apiUri, this.session.APIKEY)).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);

                js.MaxJsonLength = int.MaxValue;
                return js.Deserialize<T>(result.Content.ReadAsStringAsync().Result);
            }
        }

        private void Post<T>(string uri, T value)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var apiUri = System.IO.Path.Combine(this.ApiUri, uri);
                var result = client.PostAsJsonAsync<T>(apiUri, value).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK &&
                    result.StatusCode != System.Net.HttpStatusCode.NoContent)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);
            }
        }

        private void Put<T>(string uri, T value)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var apiUri = System.IO.Path.Combine(this.ApiUri, uri);
                var result = client.PutAsJsonAsync<T>(apiUri, value).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK && 
                    result.StatusCode != System.Net.HttpStatusCode.NoContent)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);
            }
        }

        private void Delete(string uri)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var apiUri = System.IO.Path.Combine(this.ApiUri, uri);
                var result = client.DeleteAsync(apiUri).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK &&
                    result.StatusCode != System.Net.HttpStatusCode.NoContent)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);
            }
        }

        private System.IO.Stream Download(string uri)
        {
            return this.Download(uri, String.Empty);
        }

        private System.IO.Stream Download(string uri, string contentType)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                if (!String.IsNullOrEmpty(contentType))
                    client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(contentType));

                var apiUri = System.IO.Path.Combine(this.ApiUri, uri);
                var result = client.GetAsync(apiUri).Result;

                if (result.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new Exception(result.Content.ReadAsStringAsync().Result);

                return result
                    .Content
                    .ReadAsStreamAsync()
                    .Result;
            }
        }

        private async Task<HttpResponseMessage> Upload(string uri, System.IO.Stream stream, string fileName)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var apiUri = System.IO.Path.Combine(this.ApiUri, uri);

                using (var content = new System.Net.Http.MultipartFormDataContent())
                {
                    var fileContent = new System.Net.Http.StreamContent(stream);
                    fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
                    {
                        FileName = fileName
                    };

                    content.Add(fileContent);

                    var result = await client.PostAsync(apiUri, content);            
                    return result;
                }
            }
        }

        private HttpResponseMessage UploadSync(string uri, System.IO.Stream stream, string fileName)
        {
            using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
            {
                var apiUri = System.IO.Path.Combine(this.ApiUri, uri);

                using (var content = new System.Net.Http.MultipartFormDataContent())
                {
                    var fileContent = new System.Net.Http.StreamContent(stream);
                    fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
                    {
                        FileName = fileName
                    };

                    content.Add(fileContent);
                    return client.PostAsync(apiUri, content).Result;
                }
            }
        }

    }
}
